package net.lastcoder.ifserver.packet;

import net.lastcoder.ifserver.Constants;
import net.lastcoder.ifserver.session.UlaID;
import net.lastcoder.ifserver.util.CRC32;
import net.lastcoder.ifserver.util.DataTypeUtil;
import net.lastcoder.ifserver.util.QuickCrypter;

import org.apache.mina.core.buffer.IoBuffer;
import org.json.JSONException;
import org.json.JSONObject;

import java.nio.charset.Charset;

/**
 * auth: WenYF
 * date: 2016/9/29
 */
public abstract class Packet {
    public static final byte TYPE_SET = 0;
    public static final byte TYPE_GET = 1;
    public static final byte TYPE_RESULT = 2;
    public static final byte TYPE_ERROR = 3;

    public static final byte TYPE_NONE = 127;

    protected static final Charset charset = Constants.DEFAUT_CAHRSET;
    UlaID fromUlaID;
    UlaID toUlaID;
    int id = Packet.generateId();

    public String getFrom() {
        return fromUlaID.getUsername();
    }

    public String getTo() {
        if (toUlaID != null) {
            return toUlaID.getUsername();
        } else {
            return null;
        }
    }

    public UlaID getFromAddress() {
        return fromUlaID;
    }

    public UlaID getToAddress() {
        return toUlaID;
    }

    public int getId() {
        return id;
    }

    public void setToAddress(UlaID ulaId) {
        this.toUlaID = ulaId;
    }

    public void setId(int id) {
        this.id = id;
    }
    public void setId(String strId) {
        int value  = (int) (Math.random() * 1024);
        for (byte b : strId.getBytes()) {
            value *= b;
        }
        this.id = value;
    }

    public void setFromAddress(UlaID ulaid) {
        this.fromUlaID = ulaid;
    }

    /**
     * @param isBinary    是否是二进制协议的
     * @return 永远都不能为null
     */
    protected abstract byte[] getContent(boolean isBinary);

    /**
     * @return 包的类型
     */
    public abstract byte getPacketType();

    public String getJsonString() {
        JSONObject json = new JSONObject();
        try {
            json.put("type", getPacketType());
            json.put("id", id);
            if (toUlaID != null) {
                json.put("to", toUlaID.toAddress());
            }
            if (fromUlaID != null) {
                json.put("from", fromUlaID.toAddress());
            }
            json.put("data", new JSONObject(new String(getContent(false))));
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return json.toString();
    }

    /**
     * @return  默认是二进制协议
     */
    public IoBuffer getIoBuffer() {
        return getIoBuffer(true);
    }

    /**unParserData如果有数据，那么使用该数据来组装，否者调用getContent来得到子类的数据
     * @return
     */
    public IoBuffer getIoBuffer(boolean isBinary) {

        byte[] data;
        if (isBinary) {
            data = getBinaryData();
        } else {
            data = getJsonData();
        }

        IoBuffer buffer = IoBuffer.allocate(data.length);
        buffer.put(data);

        buffer.flip();

        //System.out.println("getIoBuffer size = " + buffer.remaining());
        return buffer;
    }

    public byte[] getRawData() {
        return getBinaryData();
    }

    private byte[] getBinaryData() {
        byte[] toBytes = new byte[0];
        if (toUlaID != null) {
            toBytes = toUlaID.toAddress().getBytes();
        }

        byte[] idBytes = DataTypeUtil.intToByteArray(id);

        byte[] fromBytes = new byte[0];
        if (fromUlaID != null) {
            fromBytes = fromUlaID.toAddress().getBytes();
        }

        byte[] content = getContent(true);

        int dataSize = 1 + idBytes.length + 2 + toBytes.length + 2 + fromBytes.length
                + 4 + content.length + 4;

        MyBuffer buffer = new MyBuffer(2 + 4 + dataSize);
        // 头
        buffer.put((byte) 0xAA);
        buffer.put((byte) 0xDD);

        // 全部数据长度
        buffer.put(DataTypeUtil.intToByteArray(dataSize));

        // 设置包类型
        buffer.put(getPacketType());
        // 设置id
        buffer.put(idBytes);
        // 设置接收者长度
        buffer.put(DataTypeUtil.shortToByteArray((short) toBytes.length));
        // 设置接收者
        buffer.put(toBytes);
        // 设置发送者长度
        buffer.put(DataTypeUtil.shortToByteArray((short) fromBytes.length));
        // 设置发送者
        buffer.put(fromBytes);
        // 设置数据长度
        buffer.put(DataTypeUtil.intToByteArray(content.length));
        // 设置数据
        buffer.put(content);

        // 全部加密
        QuickCrypter.encrypt(buffer.datas, 6, dataSize - 4);

        // 得到校验码
        CRC32 crc32 = new CRC32();
        crc32.update(buffer.datas, 6, dataSize - 4);
        int crcValue = (int) crc32.getValue();
        buffer.put(DataTypeUtil.intToByteArray(crcValue));
        //System.out.println("crcValue = " + Arrays.toString(DataTypeUtil.intToByteArray(crcValue)));


        return buffer.datas;
    }

    private byte[] getJsonData() {
        return getJsonString().getBytes();
    }

    @Override
    public String toString() {
        return "Packet{" +
                "fromUlaID=" + fromUlaID +
                ", toUlaID=" + toUlaID +
                ", id=" + id +
                ", packetType = " + getPacketType() +
                '}';
    }

    private class MyBuffer {
        byte[] datas;
        int index = 0;
        public MyBuffer(int length) {
            this.datas = new byte[length];
        }

        public MyBuffer put(byte data) {
            datas[index++] = data;
            return this;
        }

        public MyBuffer put(byte[] datas) {
            for (int i = 0; i < datas.length && index < this.datas.length; i++) {
                this.datas[index++] = datas[i];
            }

            return this;
        }
    }

    private static int sCounter = 10000000;
    public static int generateId() {
        return sCounter++;
    }

}
